﻿using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using DjangoRESTFrameworkDAL.Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Polly;
using Polly.Extensions.Http;
using Polly.Retry;

namespace DjangoRESTFrameworkDAL
{
    public class Authentication
    {
        private const string LoginUrl = "/api-auth/token/";
        private const string RefreshUrl = "/api-auth/refresh/";

        public static string RefreshToken { get; set; }

        /// <summary>
        ///     登录接口
        /// </summary>
        /// <param name="username">账号</param>
        /// <param name="password">密码</param>
        /// <returns>返回登录是否成功</returns>
        public static async Task<bool> LoginAsync(string username, string password)
        {
            Console.WriteLine($"登录{username}");
            var root = new JObject
            {
                {"username", username},
                {"password", password}
            };

            var content = new StringContent(root.ToString());
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            AsyncRetryPolicy<HttpResponseMessage> waitAndRetryPolicy = CreateWaitAndRetryAsyncPolicy();
            var response =
                await waitAndRetryPolicy.ExecuteAsync(() => RestHttpClient.Instance.PostAsync(LoginUrl, content));
            if (!response.IsSuccessStatusCode)
            {
                return false;
            }
            var repoContent = await response.Content.ReadAsStringAsync();
            var token = JsonConvert.DeserializeObject<TokenObtainPairModel>(repoContent);
            RestHttpClient.Instance.DefaultRequestHeaders.Authorization
                = new AuthenticationHeaderValue("Bearer", token.Access);
            RefreshToken = token.Refresh;
            return true;
        }


        /// <summary>
        ///     刷新token
        /// </summary>
        /// <returns></returns>
        public static async Task<bool> RefreshAsync()
        {
            Console.WriteLine("刷新token");
            var root = new JObject
            {
                {"refresh", RefreshToken}
            };

            var content = new StringContent(root.ToString());
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            AsyncRetryPolicy<HttpResponseMessage> waitAndRetryPolicy = CreateWaitAndRetryAsyncPolicy();

            // TODO: 处理token刷新失败情况
            // TODO: 当token刷新失败后，根据错误原因进行尝试
            var response =
                await waitAndRetryPolicy.ExecuteAsync(() => RestHttpClient.Instance.PostAsync(RefreshUrl, content));
            if (!response.IsSuccessStatusCode)
            {
                return false;
            }
            var repoContent = await response.Content.ReadAsStringAsync();
            var token = JsonConvert.DeserializeObject<TokenObtainPairModel>(repoContent);
            RestHttpClient.Instance.DefaultRequestHeaders.Authorization
                = new AuthenticationHeaderValue("Bearer", token.Access);
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static AsyncRetryPolicy<HttpResponseMessage> CreateWaitAndRetryAsyncPolicy()
        {
            return HttpPolicyExtensions
                .HandleTransientHttpError()
                .OrResult(response=>response.StatusCode == HttpStatusCode.ServiceUnavailable
                                    || response.StatusCode == HttpStatusCode.GatewayTimeout)
                .WaitAndRetryAsync(new[]
                {
                    TimeSpan.FromSeconds(1),
                    TimeSpan.FromSeconds(5),
                    TimeSpan.FromSeconds(10)
                });
        }
    }
}